package ro.ubbcluj.cs.damate.ws.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import ro.ubbcluj.cs.damate.persistence.entities.Event;
import ro.ubbcluj.cs.damate.persistence.entities.EventParameter;
import ro.ubbcluj.cs.damate.persistence.entities.File;
import ro.ubbcluj.cs.damate.persistence.entities.ObservedObject;
import ro.ubbcluj.cs.damate.persistence.entities.Project;
import ro.ubbcluj.cs.damate.persistence.entities.Token;
import ro.ubbcluj.cs.damate.persistence.entities.Workspace;
import ro.ubbcluj.cs.damate.services.EventService;
import ro.ubbcluj.cs.damate.services.ObservedObjectService;
import ro.ubbcluj.cs.damate.services.TokenService;
import ro.ubbcluj.cs.damate.ws.generated.PluginEventRequest;
import ro.ubbcluj.cs.damate.ws.generated.PluginEventResponse;
import ro.ubbcluj.cs.damate.ws.utils.DateUtil;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

@Endpoint
public class EventServiceEndpoint {

    @Autowired
    private TokenService tokenService;

    @Autowired
    private EventService eventService;

    @Autowired
    private ObservedObjectService observedObjectService;

    @PayloadRoot(localPart="PluginEventRequest", namespace = "http://cs.ubbcluj.ro/damate/ws")
    @ResponsePayload
    public PluginEventResponse storeEvent(@RequestPayload PluginEventRequest message) {
        Token token = tokenService.findByToken(message.getUser());
        PluginEventResponse response = new PluginEventResponse();
        if (token != null) {
            eventService.create(createEventEntity(message, token));
            response.setResponseStatusCode(200);
        } else {
            response.setResponseStatusCode(500);
        }
        return response;
    }

    private Event createEventEntity(PluginEventRequest message, Token token) {
        Event event = new Event();
        event.setEventType(eventService.findEventTypeByCode(message.getEventTypeCode()));
        event.setDate(new Timestamp(DateUtil.dateFromIso(message.getEventDate()).getTime()));
        event.setRelatedUser(token.getUser());
        event.setRelatedObject(createObservedObjectEntity(message, event, token.getIpAddress()));
        if (message.getParameters() != null && !message.getParameters().isEmpty()) {
            event.setParameters(getEventParameters(event, message.getParameters()));
        }
        return event;
    }

    private ObservedObject createObservedObjectEntity(PluginEventRequest message, Event event, String ip) {
        Workspace workspace = null;
        Project project = null;
        File file = null;
        if (message.getObservedEntity() instanceof ro.ubbcluj.cs.damate.ws.generated.Workspace) {
            workspace = observedObjectService.findWorkspace(event, ip, ((ro.ubbcluj.cs.damate.ws.generated.Workspace) message.getObservedEntity()).getPath());
            return workspace;
        } else if (message.getObservedEntity() instanceof ro.ubbcluj.cs.damate.ws.generated.Project) {
            ro.ubbcluj.cs.damate.ws.generated.Project projectNode = (ro.ubbcluj.cs.damate.ws.generated.Project)message.getObservedEntity();
            workspace = observedObjectService.findWorkspace(event, ip, projectNode.getParent().getPath());
            project = observedObjectService.findProject(event, projectNode.getName(), workspace);
            return project;
        } else if (message.getObservedEntity() instanceof ro.ubbcluj.cs.damate.ws.generated.File) {
            ro.ubbcluj.cs.damate.ws.generated.File fileNode = (ro.ubbcluj.cs.damate.ws.generated.File)message.getObservedEntity();
            workspace = observedObjectService.findWorkspace(event, ip, fileNode.getParent().getParent().getPath());
            project = observedObjectService.findProject(event, fileNode.getParent().getName(), workspace);
            file = observedObjectService.findFile(event, fileNode.getPath(), fileNode.getType(), project, workspace);
            return file;
        }
        return null;
    }

    private List<EventParameter> getEventParameters(Event event, List<ro.ubbcluj.cs.damate.ws.generated.EventParameter> parameters) {
        List<EventParameter> eventParameters = new ArrayList<EventParameter>();
        for(ro.ubbcluj.cs.damate.ws.generated.EventParameter param : parameters) {
            EventParameter eventParameter = new EventParameter();
            eventParameter.setParamName(param.getName());
            eventParameter.setParamValue(param.getValue());
            eventParameter.setEvent(event);
            eventParameters.add(eventParameter);
        }
        return eventParameters;
    }
}
